package Mqtt;

import model.MovieEvent;
import model.UrlFile;
import Controller.GameController;
import android.util.Log;

import com.ibm.mqtt.IMqttClient;
import com.ibm.mqtt.MqttClient;
import com.ibm.mqtt.MqttException;
import com.ibm.mqtt.MqttNotConnectedException;
import com.ibm.mqtt.MqttPersistence;
import com.ibm.mqtt.MqttPersistenceException;
import com.ibm.mqtt.MqttSimpleCallback;
import com.intouchtv.ari.NabDemoView;

public class MyMqqtClient implements MqttSimpleCallback {

	// This is how the Android client app will identify itself to the 
	//  message broker.
	public final String CLIENT_ID;
	
	// Implements the connection to the message broker
	IMqttClient mqttClient = null;
	
	final String BROKER_HOST = "nabdemo.dyndns.org";
	
	GameController gameController;
	MovieEvent event;
	String expectedMsg;
	String topic = "NabDemo";
	private boolean sent = false;
	
	public MyMqqtClient(String pushGroup, GameController gc, MovieEvent event, String msg)
	{
		CLIENT_ID = "nab.demo."+ (int)(Math.random() * 1000);
		connectToBroker(BROKER_HOST);
		subscribeToTopic(topic);
		gameController = gc;
		this.event = event;
		expectedMsg = msg;
	}
	
	/*******************************************************************/
	/*                                                                 */
	/*        MQTT-SPECIFIC CODE                                       */
	/*                                                                 */
	/*             methods to send and receive messages                */
	/*                                                                 */
	/*******************************************************************/
	
	// hard-coded MQTT config values
	// 
	//  the app currently uses very basic defaults for it's interactions
	//   with message brokers
	//
	//  these are hard-coded here - a useful extension could be to allow the 
	//  GUI to edit these values
	private static int             BROKER_PORT_NUM      = 1883;
	private static MqttPersistence PERSISTENCE          = null;
	private static boolean         CLEAN_START          = true;
	private static short           KEEP_ALIVE           = 5;
	private static int[]           QUALITIES_OF_SERVICE = { 0 } ;
	private static int             QUALITY_OF_SERVICE   = 0;
	private static boolean         RETAINED_PUBLISH     = false;
	
	/*
	 * Creates a connection to the specified message broker.
	 */
	public void connectToBroker(String brokerHostName)
	{		
               		
        String mqttConnSpec = "tcp://" + brokerHostName + "@" + BROKER_PORT_NUM;
        
        try
        {
        	mqttClient = MqttClient.createMqttClient(mqttConnSpec, PERSISTENCE);

        	mqttClient.connect(CLIENT_ID, CLEAN_START, KEEP_ALIVE);
        	
        }
        catch (MqttException e)
        {

        }        

        // register this client app has being able to receive messages
		mqttClient.registerSimpleHandler(this);		
	}
	
	/*
	 * Terminates a connection to the message broker.
	 */
	public void disconnectFromBroker()
	{
		try 
		{
			//mqttClient.disconnect();
			mqttClient.terminate();
		} 
		catch (Exception e) 
		{
			Log.d("MQTT", e.getMessage());
			gameController.raiseErrorMessage(e.getMessage());
		}	
	}
	
	/*
	 * Send a request to the message broker to be sent messages published with 
	 *  the specified topic name. Wildcards are allowed.	
	 */
	public void subscribeToTopic(String topicName)
	{
		
		if ((mqttClient == null) || (mqttClient.isConnected() == false))
		{
			// quick sanity check - don't try and subscribe if we don't have
			//  a connection		
		}
		else 
		{									
			try 
			{
				String[] topics = { topicName };
				mqttClient.subscribe(topics, QUALITIES_OF_SERVICE);
			} 
			catch (MqttNotConnectedException e) 
			{
				Log.d("MQQT",e.getMessage() + "\n");
			} 
			catch (IllegalArgumentException e) 
			{
				Log.d("MQQT",e.getMessage() + "\n");
			} 
			catch (MqttException e) 
			{
				Log.d("MQQT",e.getMessage() + "\n");
			}
		}
	}
	
	/*
	 * Send a request to the message broker that we no longer wish to receive
	 *   messages published with the specified topic name. 
	 */
	public void unsubscribeFromTopic(String topicName)
	{
		
		if ((mqttClient == null) || (mqttClient.isConnected() == false))
		{
			// quick sanity check - don't try and unsubscribe if we don't have
			//  a connection
			Log.d("MQTT","cannot unsubscribe - not connected to a broker" + "\n");			
		}
		else 
		{						
			try 
			{
				Log.d("MQTT","unsubscribing from " + topicName + "\n");
				String[] topics = { topicName };
				mqttClient.unsubscribe(topics);
				Log.d("MQTT","unsubscribed from " + topicName + "\n");
			} 
			catch (MqttNotConnectedException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			} 
			catch (IllegalArgumentException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			} 
			catch (MqttException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			}
		}
	}	
	
	/*
	 * Sends a message to the message broker, requesting that it be published
	 *  to the specified topic.
	 */
	public void publishToTopic(String topicName, String message)
	{
		if ((mqttClient == null) || (mqttClient.isConnected() == false))
		{
			// quick sanity check - don't try and publish if we don't have
			//  a connection
			Log.d("MQTT","cannot publish - not connected to a broker" + "\n");
		}
		else 
		{
			try 
			{
				mqttClient.publish(topicName, 
								   message.getBytes(),
								   QUALITY_OF_SERVICE, 
								   RETAINED_PUBLISH);
			} 
			catch (MqttNotConnectedException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			} 
			catch (MqttPersistenceException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			} 
			catch (IllegalArgumentException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			} 
			catch (MqttException e) 
			{
				Log.d("MQTT",e.getMessage() + "\n");
			}
		}
	}
	
	/*
	 * Called if the application loses it's connection to the message broker.
	 */
	int cLostRetries = 0;
	public void connectionLost() throws Exception 
	{
		if (!sent && cLostRetries < 3)
		{
		cLostRetries++;
		Log.d("MQTT","Connection Lost - Retrying" + "\n");
		connectToBroker(BROKER_HOST);
		subscribeToTopic(topic);
		}
	}
	
	/*
	 * Called when we want to terminate the application. Cleans up any 
	 *  MQTT-specific resources first.
	 */
	public void quit()
	{		
    	if ((mqttClient != null) || (mqttClient.isConnected()))
    	{
    		Thread worker = new Thread() {
    			public void run() {
    				try{
    				unsubscribeFromTopic(topic);
    				disconnectFromBroker();
    				}
    				catch(Exception e)
    				{
    					Log.d("NabDemo",e.getMessage());
    				}
    			}
    		};
    		worker.start();
    	}	
	}	
	
	
	
	/*
	 * Called when we receive a message from the message broker. We cannot
	 *   update the GUI from this call-back thread, so we copy the 
	 *   message data into an Android 'Message' object and publish it for 
	 *   the GUI app's handler (defined above) to display.  
	 */
	public void publishArrived(String topicName, byte[] payload, int qos, boolean retained)  
	{
			String msg = new String(payload);
			if (!sent && msg.equalsIgnoreCase(expectedMsg))
			{
				Log.d("MQTT", "Got message: " + msg);
				try {
					gameController.eventOccurred(this.event.getId());
				} catch (Exception e) {
					Log.d("NabDemo", "MQTT... " +e.getMessage());
					gameController.raiseErrorMessage(e.getMessage());
				}
				finally
				{
		    		sent = true;
				}
			}
	}   

	/******************************/
	/* end of MQTT-SPECIFIC CODE  */
	/******************************/	
}
